Lab7 - Codificação de Voz e Áudio
Profs. Celso S. Kurashima e Mário Minami
Alunos:
Neste laboratório, foram utilizadas as bibliotecas Scipy, Librosa e AudioLazy, dentro do ambiente de desenvolvimento do Google Colab, para estudar técnicas de processamento digital de sinais aplicadas na análise de áudios de voz, bem como sua codificação e modelagem, utilizando a linguagem Python.
Dentre as atividades de processamento desenvolvidas, foi possível atingir os seguintes objetivos:
Objetivos:
Determinação dos parâmetros LPC
Separação Sonora/Surda
Espectro e Envoltória LP
Comparação de Codificações MPEG
Link para o ambiente Colab utilizado no desenvolvimento desta prática:
Importando todas as Bibliotecas utilzadas durante esta prática de laboratório:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
import librosa
import librosa.display
import IPython.display
import math
!pip install audiolazy
import audiolazy as lz
Adquirindo os Arquivos de áudio do repositório do GitHub:
!wget -q Entre_Leva_Catia_Falada.wav https://raw.githubusercontent.com/gabrielsouza-oss/CSM/main/labs/Entre_Leva_Catia_Falada.wav
!wget -q "minha_terra.wav" https://raw.githubusercontent.com/JohnGarrido/ESTI019/main/lab_7/minha_terra.wav
!wget -q "Voz Lida.ogg" https://raw.githubusercontent.com/gabrielsouza-oss/CSM/main/labs/LAB6/Voz%20Lida.ogg
audio1 = '/content/Entre_Leva_Catia_Falada.wav'
print(audio1)
v1 , sr1 = librosa.load(audio1)
print(type(v1), type(sr1))
print(v1.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v1, rate=sr1)
/content/Entre_Leva_Catia_Falada.wav <class 'numpy.ndarray'> <class 'int'> (292805,) 22050
plt.figure()
fig, ax = plt.subplots(figsize=(15, 5))
librosa.display.waveplot(v1, sr=sr1)
plt.title('Voz da Aryane' + audio1)
Text(0.5, 1.0, 'Voz da Aryane/content/Entre_Leva_Catia_Falada.wav')
<Figure size 432x288 with 0 Axes>
fa = sr1
Ts = 0.04
Nj = int(Ts*fa)
Nseg = int(len(v1)/Nj)
Nover = int(Nj*0.5)
from scipy import signal
hm = signal.get_window('hamming', Nj)
plt.plot(hm)
[<matplotlib.lines.Line2D at 0x7f2b32186a50>]
# Só a primeira estrofe
v11 = v1[1:64000]
plt.figure()
fig11, ax11 = plt.subplots(figsize=(15, 3))
librosa.display.waveplot(v11, sr=sr1)
plt.title('Voz da Aryane Primeira Estrofe' + audio1)
print(type(v11), type(sr1))
print(v11.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v11, rate=sr1)
<class 'numpy.ndarray'> <class 'int'> (63999,) 22050
<Figure size 432x288 with 0 Axes>
Nesta Parte do laboratório, determinamos os parâmetros LPC para modelagem das vozes, através da resposta em frequência do Filtro com os parâmetros LPC, através da função signal.freqz(1,a_filter.numerator,worN=int(Nj/2)).
Adicionalmente, pudemos determinar o número de sonoros e surdos, de acordo com um limiar de amplitude do espectro de energia do áudio analisado.
Finalmente, foi possível plotar os gráficos dos segmentos sonoros e surdos do trecho extraído do aúdio original, trazendo a resposta em frequência do filtro LPC modelado, bem como a transformada de fourier para o sinal no trecho analisado.
Nover = int(Nj*0.5)
Nseg1 = int(len(v11)/Nj)
p = 10
E = []
ind_voz = [0]*Nseg1
t = np.arange(Nj)
for l in range(1, Nseg1-1):
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
x2 = list(np.array(xjan**2))
aux = sum(x2)/Nj
E.append(aux)
E1 = 10*np.log10(E)
E1min = np.min(E1)
E1 = E1 - E1min # Coloca o ruído de fundo em 0 dB
E1max = np.max(E1)
# limiar de atividade VAD
E1VAD_lim = E1max - 8
print('Limiar VAD ' + str(E1VAD_lim))
# Limiar U/UV ajustado para 30% do máximo
E1voiced_lim = E1max - 5.3
print('Limiar U/UV ' + str(E1voiced_lim))
# indicador de VAD
ind_voz = np.where(E1 > E1VAD_lim, 1, 0)
ind_voiced = np.where(E1 > E1voiced_lim, 1, 0)
tot_voz = np.sum(ind_voz)
num_voiced = np.sum(ind_voiced)
num_unvoiced = tot_voz - num_voiced
linhas_voiced = math.ceil(num_voiced/4)
linhas_unvoiced = math.ceil(num_unvoiced/4)
print('Sonoros = ' + str(num_voiced) + ' e Surdos = ' + str(num_unvoiced) )
fig1, ax1 = plt.subplots(figsize=(15, 3))
plt.figure(1)
plt.plot(E1)
plt.title('Energia da Voz Primeira Estrofe, ' + audio1)
# partição das figuras voiced
i = 0
fig2, ax2 = plt.subplots(figsize=(20, num_voiced + linhas_voiced))
plt.title('Segmentos Sonoros (Voiced)', color = 'b')
# partição das figuras unvoiced
j = 0
fig3, ax3 = plt.subplots(figsize=(20, num_unvoiced + linhas_unvoiced))
plt.title('Segmentos Surdos (Unvoiced)', color = 'g')
for l in range(1, Nseg1-2):
# teste de VAD
if ind_voz[l] == 1:
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
a_filter = lz.lpc.kautocor(xjan, p)
gain_lpc = np.log10(abs(a_filter.error))
w, h = signal.freqz(1,a_filter.numerator,worN=int(Nj/2))
LP = 20 * np.log10(abs(h)) + 10*gain_lpc
# Teste U/UV
if E1[l] > E1voiced_lim:
i += 1
ax2 = fig2.add_subplot(linhas_voiced,4,i)
plt.figure(2)
plt.plot(w, LP, 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='b')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
else:
j += 1
ax3 = fig3.add_subplot(linhas_unvoiced,4,j)
plt.figure(3)
plt.plot(w, LP, 'g')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='g')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
Limiar VAD 7.528272731468608 Limiar U/UV 10.228272731468607 Sonoros = 28 e Surdos = 8
audio2 = '/content/minha_terra.wav'
print(audio2)
v1 , sr1 = librosa.load(audio2)
print(type(v1), type(sr1))
print(v1.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v1, rate=sr1)
/content/minha_terra.wav <class 'numpy.ndarray'> <class 'int'> (383968,) 22050
fa = sr1
Ts = 0.04
Nj = int(Ts*fa)
Nseg = int(len(v1)/Nj)
Nover = int(Nj*0.5)
from scipy import signal
hm = signal.get_window('hamming', Nj)
plt.plot(hm)
[<matplotlib.lines.Line2D at 0x7f2b31bf4a90>]
# Só a primeira estrofe
v11 = v1[1:64000]
plt.figure()
fig11, ax11 = plt.subplots(figsize=(15, 3))
librosa.display.waveplot(v11, sr=sr1)
plt.title('Primeira Estrofe Voz ' + audio2)
print(type(v11), type(sr1))
print(v11.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v11, rate=sr1)
<class 'numpy.ndarray'> <class 'int'> (63999,) 22050
<Figure size 432x288 with 0 Axes>
Nesta Parte do laboratório, determinamos os parâmetros LPC para modelagem das vozes, através da resposta em frequência do Filtro com os parâmetros LPC, através da função signal.freqz(1,a_filter.numerator,worN=int(Nj/2)).
Adicionalmente, pudemos determinar o número de sonoros e surdos, de acordo com um limiar de amplitude do espectro de energia do áudio analisado.
Finalmente, foi possível plotar os gráficos dos segmentos sonoros e surdos do trecho extraído do aúdio original, trazendo a resposta em frequência do filtro LPC modelado, bem como a transformada de fourier para o sinal no trecho analisado.
Nover = int(Nj*0.5)
Nseg1 = int(len(v11)/Nj)
p = 10
E = []
ind_voz = [0]*Nseg1
t = np.arange(Nj)
for l in range(1, Nseg1-1):
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
x2 = list(np.array(xjan**2))
aux = sum(x2)/Nj
E.append(aux)
E1 = 10*np.log10(E)
E1min = np.min(E1)
E1 = E1 - E1min # Coloca o ruído de fundo em 0 dB
E1max = np.max(E1)
# limiar de atividade VAD
E1VAD_lim = E1max - 8
print('Limiar VAD ' + str(E1VAD_lim))
# Limiar U/UV ajustado para 30% do máximo
E1voiced_lim = E1max - 5.3
print('Limiar U/UV ' + str(E1voiced_lim))
# indicador de VAD
ind_voz = np.where(E1 > E1VAD_lim, 1, 0)
ind_voiced = np.where(E1 > E1voiced_lim, 1, 0)
tot_voz = np.sum(ind_voz)
num_voiced = np.sum(ind_voiced)
num_unvoiced = tot_voz - num_voiced
linhas_voiced = math.ceil(num_voiced/4)
linhas_unvoiced = math.ceil(num_unvoiced/4)
print('Sonoros = ' + str(num_voiced) + ' e Surdos = ' + str(num_unvoiced) )
fig1, ax1 = plt.subplots(figsize=(15, 3))
plt.figure(1)
plt.plot(E1)
plt.title('Energia da Voz Primeira Estrofe, ' + audio2)
# partição das figuras voiced
i = 0
fig2, ax2 = plt.subplots(figsize=(20, num_voiced + linhas_voiced))
plt.title('Segmentos Sonoros (Voiced)', color = 'b')
# partição das figuras unvoiced
j = 0
fig3, ax3 = plt.subplots(figsize=(20, num_unvoiced + linhas_unvoiced))
plt.title('Segmentos Surdos (Unvoiced)', color = 'g')
for l in range(1, Nseg1-2):
# teste de VAD
if ind_voz[l] == 1:
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
a_filter = lz.lpc.kautocor(xjan, p)
gain_lpc = np.log10(abs(a_filter.error))
w, h = signal.freqz(1,a_filter.numerator,worN=int(Nj/2))
LP = 20 * np.log10(abs(h)) + 10*gain_lpc
# Teste U/UV
if E1[l] > E1voiced_lim:
i += 1
ax2 = fig2.add_subplot(linhas_voiced,4,i)
plt.figure(2)
plt.plot(w, LP, 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='b')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
else:
j += 1
ax3 = fig3.add_subplot(linhas_unvoiced,4,j)
plt.figure(3)
plt.plot(w, LP, 'g')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='g')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
Limiar VAD 29.052105199617557 Limiar U/UV 31.752105199617557 Sonoros = 12 e Surdos = 16
Nesta parte do laboratório, pudemos visualizar os espectrogramas dos áudios gravados pelos integrantes, mostrando a potência, em escala de decibéis (dB), bem como o espectrograma de frequência para cada um dos áudios originais.
Para converter a amplitude para Decibéis, foi utilizada a função librosa.amplitude_to_db(), tomando como referência o valor máximo do espectro.
Para plotar o gráfico, utilizamos a função librosa.display.specshow()
Abaixo, temos a Função desenvolvida para plotar os espectrogramas (em decibéis), dos arquivos de áudio do grupo, utilizando as bilbioteca Librosa e MatplotLib para visualização do espectro
def visualizao_especto(v1,path):
plt.figure(figsize=(12, 8))
D = librosa.amplitude_to_db(np.abs(librosa.stft(v1)), ref=np.max)
fig, ax = plt.subplots(figsize=(15, 10))
librosa.display.specshow(D, x_axis='time',y_axis='linear')
plt.colorbar(format='%+2.0f dB')
plt.title('Potência e Espectrograma Linear na Frequência '+ path)
plt.show()
visualizao_especto(v1,"minha_terra.wav")
<Figure size 864x576 with 0 Axes>
audio3 = '/content/Voz Lida.ogg'
print(audio3)
v1 , sr1 = librosa.load(audio3)
print(type(v1), type(sr1))
print(v1.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v1, rate=sr1)
/content/Voz Lida.ogg
/usr/local/lib/python3.7/dist-packages/librosa/core/audio.py:165: UserWarning: PySoundFile failed. Trying audioread instead.
warnings.warn("PySoundFile failed. Trying audioread instead.")
<class 'numpy.ndarray'> <class 'int'> (386757,) 22050
fa = sr1
Ts = 0.04
Nj = int(Ts*fa)
Nseg = int(len(v1)/Nj)
Nover = int(Nj*0.5)
from scipy import signal
hm = signal.get_window('hamming', Nj)
plt.plot(hm)
[<matplotlib.lines.Line2D at 0x7f2b31bb26d0>]
# Só a primeira estrofe
v11 = v1[1:64000]
plt.figure()
fig11, ax11 = plt.subplots(figsize=(15, 3))
librosa.display.waveplot(v11, sr=sr1)
plt.title('Primeira Estrofe ' + audio3)
print(type(v11), type(sr1))
print(v11.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v11, rate=sr1)
<class 'numpy.ndarray'> <class 'int'> (63999,) 22050
<Figure size 432x288 with 0 Axes>
Nesta Parte do laboratório, determinamos os parâmetros LPC para modelagem das vozes, através da resposta em frequência do Filtro com os parâmetros LPC, através da função signal.freqz(1,a_filter.numerator,worN=int(Nj/2)).
Adicionalmente, pudemos determinar o número de sonoros e surdos, de acordo com um limiar de amplitude do espectro de energia do áudio analisado.
Finalmente, foi possível plotar os gráficos dos segmentos sonoros e surdos do trecho extraído do aúdio original, trazendo a resposta em frequência do filtro LPC modelado, bem como a transformada de fourier para o sinal no trecho analisado.
Nover = int(Nj*0.5)
Nseg1 = int(len(v11)/Nj)
p = 10
E = []
ind_voz = [0]*Nseg1
t = np.arange(Nj)
for l in range(1, Nseg1-1):
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
x2 = list(np.array(xjan**2))
aux = sum(x2)/Nj
E.append(aux)
E1 = 10*np.log10(E)
E1min = np.min(E1)
E1 = E1 - E1min # Coloca o ruído de fundo em 0 dB
E1max = np.max(E1)
# limiar de atividade VAD
E1VAD_lim = E1max - 8
print('Limiar VAD ' + str(E1VAD_lim))
# Limiar U/UV ajustado para 30% do máximo
E1voiced_lim = E1max - 5.3
print('Limiar U/UV ' + str(E1voiced_lim))
# indicador de VAD
ind_voz = np.where(E1 > E1VAD_lim, 1, 0)
ind_voiced = np.where(E1 > E1voiced_lim, 1, 0)
tot_voz = np.sum(ind_voz)
num_voiced = np.sum(ind_voiced)
num_unvoiced = tot_voz - num_voiced
linhas_voiced = math.ceil(num_voiced/4)
linhas_unvoiced = math.ceil(num_unvoiced/4)
print('Sonoros = ' + str(num_voiced) + ' e Surdos = ' + str(num_unvoiced) )
fig1, ax1 = plt.subplots(figsize=(15, 3))
plt.figure(1)
plt.plot(E1)
plt.title('Energia da Voz Primeira Estrofe, ' + audio3)
# partição das figuras voiced
i = 0
fig2, ax2 = plt.subplots(figsize=(20, num_voiced + linhas_voiced))
plt.title('Segmentos Sonoros (Voiced)', color = 'b')
# partição das figuras unvoiced
j = 0
fig3, ax3 = plt.subplots(figsize=(20, num_unvoiced + linhas_unvoiced))
plt.title('Segmentos Surdos (Unvoiced)', color = 'g')
for l in range(1, Nseg1-2):
# teste de VAD
if ind_voz[l] == 1:
xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
a_filter = lz.lpc.kautocor(xjan, p)
gain_lpc = np.log10(abs(a_filter.error))
w, h = signal.freqz(1,a_filter.numerator,worN=int(Nj/2))
LP = 20 * np.log10(abs(h)) + 10*gain_lpc
# Teste U/UV
if E1[l] > E1voiced_lim:
i += 1
ax2 = fig2.add_subplot(linhas_voiced,4,i)
plt.figure(2)
plt.plot(w, LP, 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='b')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
else:
j += 1
ax3 = fig3.add_subplot(linhas_unvoiced,4,j)
plt.figure(3)
plt.plot(w, LP, 'g')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [rad/sample] - Segmento: ' + str(l), color='g')
sp = np.fft.fft(xjan)
plt.plot(w, 20*np.log10(abs(sp[0:int(Nj/2)])), 'r')
Limiar VAD 81.0592499683971 Limiar U/UV 83.7592499683971 Sonoros = 2 e Surdos = 9
visualizao_especto(v1,"/content/Voz Lida.ogg")
<Figure size 864x576 with 0 Axes>
Neste laboratório, através da manipulação de dados de áudio, foi possível aplicar técnicas de análise de sinais em arquivos de áudio/voz.
Através das bibliotecas scipy e librosa e audiolazy, foi possível realizar processos de análiticos para exploração de segmentos e amostras de áudio.
A partir dos sinais analisados, foram extraídas componentes como:
Desta forma, através da determinação dos segmentos sonoros e surdos que se deu através da análise do limiar do espectro energia do áudio, pudemos estudar separadamente as repostas em frequência do modelo de filtro LPC, versus a resposta fornecida pela transformada de Fourier aplicada à cada trecho dos áudios analisados.